package com.jmectf.net.console;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashMap;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;

/**
 * <code>ServerConsole</code> is a console that used to run and manage a jmectf
 * server, among other things. The user should have JRE 1.6.0.10 or higher
 * installed for optimal performance.
 * 
 * @author Lev Krayzman, Nilay Kumar
 * @version June 17, 2009 12:20 A.M.
 * 
 */
public class ServerConsole extends JFrame {

	private static final long serialVersionUID = 1L;
	private static final String PROMPT = "[jmectf]$ ";
	private JTextArea textArea;
	private ServerThread serverThread;
	private boolean serverStarted = false;
	HashMap<String, String> man;
	ServerInfo info;
	private final String helpString = "\n\n\t= jmectf console help =\n"
		+ "exit: exit the console\n" + "help: prints this message\n"
		+ "help [command]: prints the command's help/man page\n"
		+ "new server: starts a new battle server\n"
		+ "quit: exit the console\n";

	/**
	 * Constructor creates a new <code>ServerConsole</code>. Mostly, it sets up
	 * the GUI for the console.
	 */
	public ServerConsole() {
		super("jmectf - SERVER");
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		Dimension frameSize = new Dimension((int) (screenSize.width / 2),
				(int) (screenSize.height / 2));
		int x = (int) (0);
		int y = (int) (0);
		setBounds(x, y, frameSize.width, frameSize.height);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		textArea = new JTextArea();
		JScrollPane scroll = new JScrollPane(textArea,
				ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
				ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
		textArea.setEditable(false);
		textArea.setFont(new Font("Courier New", Font.PLAIN, 13));
		textArea.setBackground(Color.black);
		textArea.setForeground(Color.green);
		textArea.setLineWrap(true);
		textArea.append(PROMPT);
		getContentPane().setLayout(new BorderLayout());
		getContentPane().add(scroll, BorderLayout.CENTER);
		textArea.addKeyListener(new KeyHandler());
		com.sun.awt.AWTUtilities.setWindowOpacity(this, 0.8f);
		initializeManual();
		setVisible(true);
	}

	/**
	 * Method <code>initializeManual</code> initializes a <code>HashMap</code>
	 * that holds the information about every valid command.
	 */
	public void initializeManual() {
		man = new HashMap<String, String>();
		man.put("exit", "Exits the program with exit status 0.");
		man.put("help", "Now, honestly...?");
		man.put("new server", "Starts a new battle server.");
		man.put("quit", man.get("exit"));
	}

	/**
	 * <code>main</code> defines the entry point of the program.
	 * 
	 * @param args
	 *            command-line arguments.
	 */
	public static void main(String args[]) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				new ServerConsole();
			}
		});
	}

	public void updateConsole(String s) {
		// change this to update the info window
		textArea.append(s);
	}

	/**
	 * <code>KeyHandler</code> is a private inner class that handles the user's
	 * key input.
	 * 
	 * @author Nilay Kumar
	 * @version June 17, 2009 12:20 A.M.
	 */
	private class KeyHandler implements KeyListener {

		@Override
		public void keyPressed(KeyEvent arg0) {
			handleEvent(arg0);
		}

		@Override
		public void keyReleased(KeyEvent arg0) {
		}

		@Override
		public void keyTyped(KeyEvent arg0) {
		}

		/**
		 * Method <code>handleEvent</code> reads key input and processes it.
		 * 
		 * @param event
		 *            - The <code>KeyEvent</code> that information about the
		 *            user's' input is extracted from
		 */
		private void handleEvent(KeyEvent event) {
			if (event.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
				if (getThisLine().length() > 0) {
					String buffer = textArea.getText();
					buffer = buffer.substring(0, buffer.length() - 1);
					textArea.setText(buffer);
				} else
					return;
			} else if (event.getKeyCode() == KeyEvent.VK_ENTER) {
				if (!processCommand(getThisLine().toLowerCase().trim()))
					textArea
					.append("\n\'" + getThisLine().toLowerCase().trim() 
							+ "\' is not recognized as an internal or external command or an operable program.");
				textArea.append("\n" + PROMPT);
				return;
			} else if (!event.isActionKey()
					&& event.getKeyCode() != KeyEvent.VK_SHIFT
					&& event.getKeyCode() != KeyEvent.VK_ALT
					&& event.getKeyCode() != KeyEvent.VK_CONTROL)
				textArea.append(event.getKeyChar() + "");
		}

		/**
		 * Method <code>processCommand</code> processes the commands that the
		 * user enters
		 * 
		 * @param command
		 *            - The command entered by the user
		 * @return true if the command is valid, false if it is malformed or
		 *         invalid.
		 */
		private boolean processCommand(String command) {
			if (command.equals("exit") || command.equals("quit"))
				if (!serverStarted)
					System.exit(0);
				else {
					serverStarted = false;
					serverThread.close();
					return true;
				}
			else if (command.length() >= 10 && command.equals("new server")) {
				if (serverStarted) {
					textArea.append("\nServer is already online.");
					return true;
				}
				serverStarted = true;
				serverThread = new ServerThread(ServerConsole.this, info);
				serverThread.start();
				return true;
			} else if (command.equals("help")) {
				textArea.append(helpString);
				return true;
			} else if (command.length() > 5 && command.substring(0, 5).equals("help ")) {
				String tempMan = man.get(command.substring(5));
				if (tempMan != null) {
					textArea.append("\n" + tempMan);
					return true;
				}
				textArea.append("\nNo help topics match \'" + command.substring(5) + "\'.");
				return true;
			}
			return false;
		}

		/**
		 * Method <code>getThisLine</code> gets the user's input on the current
		 * line.
		 * 
		 * @return The text on the current prompt line
		 */
		private String getThisLine() {
			return textArea.getText().substring(textArea.getText().lastIndexOf(PROMPT) + PROMPT.length());
		}
	}
}
